package org.jeecg.modules.carInformationUpload.controller;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.aspect.annotation.AutoLog;
import org.jeecg.common.system.base.controller.JeecgController;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.util.CommonUtils;
import org.jeecg.modules.carInformationUpload.entity.CarInformationUpload;
import org.jeecg.modules.carInformationUpload.entity.EntryExitStatus;
import org.jeecg.modules.carInformationUpload.service.ICarInformationUploadService;
import org.jeecg.modules.carInformationUpload.util.Base64ToMultipartFile;
import org.jeecg.modules.carLedger.entity.CarLedger;
import org.jeecg.modules.carLedger.service.ICarLedgerService;
import org.jeecg.modules.carRecord.entity.CarRecord;
import org.jeecg.modules.carRecord.service.ICarRecordService;
import org.jeecg.modules.carRegister.entity.CarRegister;
import org.jeecg.modules.carRegister.service.ICarRegisterService;
import org.jeecg.modules.ledgerBaseInfo.entity.LedgerBaseInfo;
import org.jeecg.modules.ledgerBaseInfo.service.ILedgerBaseInfoService;
import org.jeecg.modules.networking.service.INetWorkingService;
import org.jeecg.modules.networking.util.GoodsMapper;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.Date;

/**
 * @Description: 进出厂车辆信息上传表
 * @Author: jeecg-boot
 * @Date:   2024-07-23
 * @Version: V1.0
 */
@Api(tags="进出厂车辆信息上传表")
@RestController
@RequestMapping("/carInformationUpload/carInformationUpload")
@Slf4j
public class CarInformationUploadController extends JeecgController<CarInformationUpload, ICarInformationUploadService> {
	@Value(value = "${jeecg.uploadType}")
	private String uploadType;
	@Autowired
	private ICarInformationUploadService carInformationUploadService;
	@Autowired
	private ICarRecordService carRecordService;
	@Autowired
	private ICarLedgerService carLedgerService;
	@Autowired
	private ICarRegisterService carRegisterService;
	@Autowired
	private INetWorkingService netWorkingService;
	@Autowired
	private ILedgerBaseInfoService ledgerBaseInfoService;

	/**
	 * 分页列表查询
	 *
	 * @param carInformationUpload 对象
	 * @param pageNo 页数
	 * @param pageSize 每页大小
	 * @param req 请求
	 * @return Result
	 */
	@AutoLog(value = "进出厂车辆信息上传表-分页列表查询")
	@ApiOperation(value="进出厂车辆信息上传表-分页列表查询", notes="进出厂车辆信息上传表-分页列表查询")
	@GetMapping(value = "/list")
	public Result<?> queryPageList(CarInformationUpload carInformationUpload,
								   @RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
								   @RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
								   HttpServletRequest req) {
		QueryWrapper<CarInformationUpload> queryWrapper = QueryGenerator.initQueryWrapper(carInformationUpload, req.getParameterMap());
		Page<CarInformationUpload> page = new Page<CarInformationUpload>(pageNo, pageSize);
		IPage<CarInformationUpload> pageList = carInformationUploadService.page(page, queryWrapper);
		return Result.OK(pageList);
	}

	 @AutoLog(value = "进出厂车辆信息上传表-对外-分页列表查询")
	 @ApiOperation(value="进出厂车辆信息上传表-对外-分页列表查询", notes="进出厂车辆信息上传表-对外-分页列表查询")
	 @GetMapping(value = "/m/list")
	 public Result<?> mQueryPageList(CarInformationUpload carInformationUpload,
									@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
									@RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
									HttpServletRequest req) {
		 QueryWrapper<CarInformationUpload> queryWrapper = QueryGenerator.initQueryWrapper(carInformationUpload, req.getParameterMap());
		 queryWrapper.orderByDesc("create_time");
		 Page<CarInformationUpload> page = new Page<CarInformationUpload>(pageNo, pageSize);
		 IPage<CarInformationUpload> pageList = carInformationUploadService.page(page, queryWrapper);
		 return Result.OK(pageList);
	 }

	/**
	 *   添加
	 *
	 * @param jsonObject 对象
	 * @return Result
	 */
	@AutoLog(value = "进出厂车辆信息上传表-移动端-上传")
	@ApiOperation(value="进出厂车辆信息上传表-移动端-上传", notes="进出厂车辆信息上传表-移动端-上传")
	@PostMapping(value = "/m/appUpload")
	public Result<?> appUpload(@RequestBody JSONObject jsonObject){
		String gateNumber = jsonObject.getString("gateNumber");
		String barrierGateNumber = jsonObject.getString("barrierGateNumber");
		EntryExitStatus entryExitStatus = EntryExitStatus.fromValue(jsonObject.getString("entryExitStatus"));
		String carType = jsonObject.getString("carType");
		String plateNo = jsonObject.getString("plateNo");
		String plateColor = jsonObject.getString("plateColor");
		String entryExitTime = jsonObject.getString("entryExitTime");
		String entryExitPic = jsonObject.getString("entryExitPic");
		Date date = stringToDate(entryExitTime);
		if (entryExitStatus == EntryExitStatus.ENTRY) {
			if ("1".equals(carType)) { // 入台账
				CarRegister oneByPlateNo = carRegisterService.getLastByPlateNo(plateNo);
				if (oneByPlateNo != null) {
					CarInformationUpload carInformationUpload = getInformationUpload(oneByPlateNo,
							gateNumber, barrierGateNumber, entryExitStatus, date, entryExitPic, entryExitPic);
					CarLedger carLedger = getCarLedger(oneByPlateNo, gateNumber,
							barrierGateNumber, date, entryExitPic, null);
					if (1 != oneByPlateNo.getWhiteList()){
						oneByPlateNo.setEntryStatus(1); // 已入场
					}
					carRegisterService.updateById(oneByPlateNo);
					carInformationUploadService.save(carInformationUpload);
					carLedgerService.save(carLedger);
				} else {
					return Result.error("该车辆未登记!");
				}
			}
			createOrUpdateCarRecord(plateNo, plateColor, barrierGateNumber, date, entryExitPic, true);
		} else if (entryExitStatus == EntryExitStatus.EXIT) {
			if ("1".equals(carType)) { // 入台账
				CarLedger lastByPlateNo = carLedgerService.getLastByPlateNo(plateNo);
				if (lastByPlateNo != null) {
					CarInformationUpload carInformationUpload = getInformationUpload(lastByPlateNo,
							gateNumber, barrierGateNumber, entryExitStatus, date, entryExitPic, entryExitPic);
					lastByPlateNo.setExitPic(entryExitPic).setExitTime(date);
					carLedgerService.updateById(lastByPlateNo);
					carInformationUploadService.save(carInformationUpload);
				} else {
					CarRegister oneByPlateNo = carRegisterService.getOneByPlateNo(plateNo);
					if (oneByPlateNo != null) {
						CarLedger carLedger = new CarLedger();
						BeanUtils.copyProperties(oneByPlateNo, carLedger);
						carLedger.setGateNumber(gateNumber).setExitBarrierGate(barrierGateNumber)
								.setExitTime(date).setExitPic(entryExitPic);
						CarInformationUpload carInformationUpload = getInformationUpload(oneByPlateNo,
								gateNumber, barrierGateNumber, entryExitStatus, date, entryExitPic, entryExitPic);
						carLedgerService.save(carLedger);
						carInformationUploadService.save(carInformationUpload);
					}
				}
			}
			createOrUpdateCarRecord(plateNo, plateColor, barrierGateNumber, date, entryExitPic, false);
		} else {
			return Result.error("进出场状态不正确");
		}
		return Result.OK("上传成功", null);
	}

	/**
	 *   添加
	 *
	 * @param jsonObject 对象
	 * @return Result
	 */
	@AutoLog(value = "进出厂车辆信息上传表-客户端-上传")
	@ApiOperation(value="进出厂车辆信息上传表-客户端-上传", notes="进出厂车辆信息上传表-客户端-上传")
	@PostMapping(value = "/m/upload")
	public Result<?> mUpload(@RequestBody JSONObject jsonObject) {
		String gateNumber = jsonObject.getString("gateNumber");
		String barrierGateNumber = jsonObject.getString("barrierGateNumber");
		String carType = jsonObject.getString("carType");
		EntryExitStatus entryExitStatus = EntryExitStatus.fromValue(jsonObject.getString("entryExitStatus"));
		String plateNo = jsonObject.getString("plateNo");
		String plateColor = jsonObject.getString("plateColor");
		String entryExitTime = jsonObject.getString("entryExitTime");
		String entryExitPic = jsonObject.getString("entryExitPic");
		String highPic = jsonObject.getString("highPic");
		String goods = jsonObject.getString("goods");
		String transportGoodType = GoodsMapper.getGoodsType(jsonObject.getString("transportGoodType"));
		BigDecimal freightVolume = new BigDecimal(jsonObject.getString("freightVolume")).divide(BigDecimal.valueOf(1000), 5, RoundingMode.HALF_UP);
		MultipartFile multipartFile = new Base64ToMultipartFile(entryExitPic, "png", "image/png");
		String bizPath = DateUtil.formatDate(new Date());
		String savePath = CommonUtils.upload(multipartFile, bizPath, uploadType);
		String highPath = null;
		if (highPic != null && !highPic.isEmpty()){
			MultipartFile highFile = new Base64ToMultipartFile(highPic, "png", "image/png");
			highPath = CommonUtils.upload(highFile, bizPath, uploadType);
		}
		Date date = stringToDate(entryExitTime);
		if (entryExitStatus == EntryExitStatus.ENTRY) {
			if ("1".equals(carType)) {//入台账
				CarRegister oneByPlateNo = carRegisterService.getLastByPlateNo(plateNo);
				if (oneByPlateNo != null) {
					CarInformationUpload carInformationUpload = getInformationUpload(oneByPlateNo,
							gateNumber, barrierGateNumber, entryExitStatus, date, savePath, highPath);
					carInformationUpload.setGoods(goods).setTransportGoodType(transportGoodType);
					carInformationUpload.setFreightVolume(freightVolume);
					CarLedger carLedger = getCarLedger(oneByPlateNo, gateNumber,
							barrierGateNumber, date, savePath, highPath);
					LedgerBaseInfo byPlateNo = ledgerBaseInfoService.getByPlateNo(plateNo);
					if (byPlateNo == null){
						LedgerBaseInfo ledgerBaseInfo = new LedgerBaseInfo();
						BeanUtils.copyProperties(carLedger, ledgerBaseInfo);
						ledgerBaseInfoService.save(ledgerBaseInfo);
					}
					if (oneByPlateNo.getTransportStatus() == 0) {
						carLedger.setOutTransportGoods(goods);
					} else {
						carLedger.setInTransportGoods(goods);
					}
					carLedger.setInFreightVolume(freightVolume).setGoods(goods)
							.setTransportGoodType(transportGoodType);
					if (1 != oneByPlateNo.getWhiteList()){
						oneByPlateNo.setEntryStatus(1); // 已入场
					}
					carRegisterService.updateById(oneByPlateNo);
					carLedgerService.save(carLedger);
					uploadAndSaveCarInformation(carInformationUpload);
				}
			}
			createOrUpdateCarRecord(plateNo, plateColor, barrierGateNumber, date, savePath, true);
		} else if (entryExitStatus == EntryExitStatus.EXIT) {
			if ("1".equals(carType)) {//入台账
				CarLedger lastByPlateNo = carLedgerService.getLastByPlateNo(plateNo);
				if (lastByPlateNo != null) {
					CarInformationUpload carInformationUpload = getInformationUpload(lastByPlateNo,
							gateNumber, barrierGateNumber, entryExitStatus, date, savePath, highPath);
					carInformationUpload.setGoods(goods).setFreightVolume(freightVolume).setTransportGoodType(transportGoodType);
					lastByPlateNo.setExitPic(savePath).setExitTime(date).setExitHighPic(highPath)
							.setExitBarrierGate(barrierGateNumber).setOutFreightVolume(freightVolume);
					BigDecimal inFreightVolume = lastByPlateNo.getInFreightVolume();
					lastByPlateNo.setNetWeight(String.valueOf(inFreightVolume.subtract(freightVolume).abs()));
					carLedgerService.updateById(lastByPlateNo);
					uploadAndSaveCarInformation(carInformationUpload);
				} else {
					CarRegister oneByPlateNo = carRegisterService.getOneByPlateNo(plateNo);
					if (oneByPlateNo != null) {
						CarLedger carLedger = new CarLedger();
						BeanUtils.copyProperties(oneByPlateNo, carLedger);
						carLedger.setGateNumber(gateNumber).setExitBarrierGate("A02")
								.setExitTime(date).setExitPic(savePath).setExitHighPic(highPath)
								.setGoods(goods).setTransportGoodType(transportGoodType)
								.setFreightVolume(freightVolume).setOutFreightVolume(freightVolume);
						if (oneByPlateNo.getTransportStatus() == 1){
							carLedger.setInTransportGoods(goods);
						} else {
							carLedger.setOutTransportGoods(goods);
						}
						CarInformationUpload carInformationUpload = getInformationUpload(oneByPlateNo,
								gateNumber, barrierGateNumber, entryExitStatus, date, savePath, highPath);
						carInformationUpload.setGoods(goods).setTransportGoodType(transportGoodType);
						carInformationUpload.setFreightVolume(freightVolume);
						carLedgerService.save(carLedger);
						uploadAndSaveCarInformation(carInformationUpload);
					}
				}
			}
			createOrUpdateCarRecord(plateNo, plateColor, barrierGateNumber, date, savePath, false);
		} else {
			return Result.error("进出场状态不正确");
		}
		return Result.OK("上传成功", null);
	}

	private void uploadAndSaveCarInformation(CarInformationUpload carInformationUpload){
		carInformationUpload.setTransportGoodType(GoodsMapper.getGoodsType(carInformationUpload.getGoods()));
		new Thread(() -> {
			boolean uploaded = false;
			int maxRetries = 3;  // 最大重试次数
			int retryCount = 0;

			// 先尝试正常上传
			while (!uploaded && retryCount < maxRetries) {
				try {
					JSONObject response = netWorkingService.putVehiclePassRecords(carInformationUpload);
					Integer code = response.getInteger("code");
					if (code == 200) {
						carInformationUpload.setUploadStatus("1");
						uploaded = true;
					} else {
						log.warn("接口返回错误结果: {}, 重试次数: {}", response, retryCount + 1);
						retryCount++;
						if (retryCount < maxRetries) {
							Thread.sleep(2000); // 等待2秒后重试
						}
					}
				} catch (Exception e) {
					log.error("上传车辆通行记录异常: {}, 重试次数: {}", e.getMessage(), retryCount + 1, e);
					retryCount++;
					if (retryCount < maxRetries) {
						try {
							Thread.sleep(2000); // 等待2秒后重试
						} catch (InterruptedException ie) {
							Thread.currentThread().interrupt();
							break;
						}
					}
				}
			}

			// 如果多次重试后仍然失败，标记为需要补传
			if (!uploaded) {
				carInformationUpload.setUploadStatus("-1"); // 上传失败
			}
			carInformationUploadService.save(carInformationUpload);
		}).start();
	}

	private void createOrUpdateCarRecord(String plateNo, String plateColor, String barrierGateNumber,
										 Date date, String savePath, boolean isEntry) {
		CarRecord carRecord = isEntry ? new CarRecord() : carRecordService.getLastByPlateNo(plateNo);
		if (carRecord == null) {
			carRecord = new CarRecord();
		}
		carRecord.setPlateNo(plateNo).setPlateColor(plateColor)
				.setEntryPic(isEntry ? savePath : null).setEntryTime(isEntry ? date : null)
				.setExitPic(!isEntry ? savePath : null).setExitTime(!isEntry ? date : null);
		if (carRecord.getId() == null || carRecord.getId().isEmpty()) {
			carRecord.setEntryBarrierGate(barrierGateNumber);
			carRecordService.save(carRecord);
		} else {
			carRecord.setExitBarrierGate(barrierGateNumber);
			carRecordService.updateById(carRecord);
		}
	}

	private static @NotNull CarLedger getCarLedger(CarRegister oneByPlateNo, String gateNumber,
												   String barrierGateNumber, Date date,
												   String savePath, String highPath) {
		CarLedger carLedger = new CarLedger();
		BeanUtils.copyProperties(oneByPlateNo, carLedger);
		carLedger.setGateNumber(gateNumber).setEntryBarrierGate(barrierGateNumber)
				.setEntryTime(date).setEntryPic(savePath).setId(null).setCreateTime(null)
				.setCreateBy(null).setUpdateBy(null).setUpdateTime(null)
				.setEntryHighPic(highPath);
		return carLedger;
	}

	private static @NotNull CarInformationUpload getInformationUpload(CarLedger carLedger, String gateNumber,
																	  String barrierGateNumber,
																	  EntryExitStatus entryExitStatus, Date date,
																	  String savePath, String highPath) {
		CarInformationUpload carInformationUpload = new CarInformationUpload();
		BeanUtils.copyProperties(carLedger, carInformationUpload);
		carInformationUpload.setGateNumber(gateNumber).setBarrierGateNumber(barrierGateNumber)
				.setEntryExitStatus(entryExitStatus.getValue()).setEntryExitTime(date)
				.setEntryExitPic(savePath).setHighPic(highPath).setId(null).setCreateTime(null)
				.setCreateBy(null).setUpdateBy(null).setUpdateTime(null);
		return carInformationUpload;
	}

	private static @NotNull CarInformationUpload getInformationUpload(CarRegister oneByPlateNo,
																	  String gateNumber, String barrierGateNumber,
																	  EntryExitStatus entryExitStatus, Date date,
																	  String savePath, String highPath) {
		CarInformationUpload carInformationUpload = new CarInformationUpload();
		BeanUtils.copyProperties(oneByPlateNo, carInformationUpload);
		carInformationUpload.setGateNumber(gateNumber).setBarrierGateNumber(barrierGateNumber)
				.setEntryExitStatus(entryExitStatus.getValue()).setEntryExitTime(date)
				.setEntryExitPic(savePath).setHighPic(highPath).setId(null).setCreateTime(null)
				.setCreateBy(null).setUpdateBy(null).setUpdateTime(null);
		return carInformationUpload;
	}

	@AutoLog(value = "进出厂车辆信息上传表-数据补传")
	@ApiOperation(value="进出厂车辆信息上传表-数据补传", notes="进出厂车辆信息上传表-数据补传")
	@PostMapping(value = "/reUpload")
	public Result<?> reUpload(@RequestBody CarInformationUpload carInformationUpload) {
		carInformationUpload.setTransportGoodType(GoodsMapper.getGoodsType(carInformationUpload.getGoods()));
		new Thread(() -> {
			try {
				JSONObject response = netWorkingService.putVehiclePassRecords(carInformationUpload);
				Integer code = response.getInteger("code");
				if (code == 200) {
					carInformationUpload.setUploadStatus("1");
				} else {
					log.warn("接口返回错误结果: {}", response);
				}
			} catch (Exception e) {
				log.error(e.getMessage(), e);
			}
			carInformationUploadService.updateById(carInformationUpload);
		}).start();
		return Result.OK("已发起补传请求", null);
	}

	/**
	 *   添加
	 *
	 * @param carInformationUpload 对象
	 * @return Result
	 */
	@AutoLog(value = "进出厂车辆信息上传表-添加")
	@ApiOperation(value="进出厂车辆信息上传表-添加", notes="进出厂车辆信息上传表-添加")
	@PostMapping(value = "/add")
	public Result<?> add(@RequestBody CarInformationUpload carInformationUpload) {
		carInformationUploadService.save(carInformationUpload);
		return Result.OK("添加成功！");
	}

	/**
	 *  编辑
	 *
	 * @param carInformationUpload 对象
	 * @return Result
	 */
	@AutoLog(value = "进出厂车辆信息上传表-编辑")
	@ApiOperation(value="进出厂车辆信息上传表-编辑", notes="进出厂车辆信息上传表-编辑")
	@PutMapping(value = "/edit")
	public Result<?> edit(@RequestBody CarInformationUpload carInformationUpload) {
		carInformationUploadService.updateById(carInformationUpload);
		return Result.OK("编辑成功!");
	}

	/**
	 *   通过id删除
	 *
	 * @param id id
	 * @return Result
	 */
	@AutoLog(value = "进出厂车辆信息上传表-通过id删除")
	@ApiOperation(value="进出厂车辆信息上传表-通过id删除", notes="进出厂车辆信息上传表-通过id删除")
	@DeleteMapping(value = "/delete")
	public Result<?> delete(@RequestParam(name="id",required=true) String id) {
		carInformationUploadService.removeById(id);
		return Result.OK("删除成功!");
	}

	/**
	 *  批量删除
	 *
	 * @param ids ids
	 * @return Result
	 */
	@AutoLog(value = "进出厂车辆信息上传表-批量删除")
	@ApiOperation(value="进出厂车辆信息上传表-批量删除", notes="进出厂车辆信息上传表-批量删除")
	@DeleteMapping(value = "/deleteBatch")
	public Result<?> deleteBatch(@RequestParam(name="ids",required=true) String ids) {
		this.carInformationUploadService.removeByIds(Arrays.asList(ids.split(",")));
		return Result.OK("批量删除成功!");
	}

	/**
	 * 通过id查询
	 *
	 * @param id id
	 * @return Result
	 */
	@AutoLog(value = "进出厂车辆信息上传表-通过id查询")
	@ApiOperation(value="进出厂车辆信息上传表-通过id查询", notes="进出厂车辆信息上传表-通过id查询")
	@GetMapping(value = "/queryById")
	public Result<?> queryById(@RequestParam(name="id",required=true) String id) {
		CarInformationUpload carInformationUpload = carInformationUploadService.getById(id);
		if(carInformationUpload==null) {
			return Result.error("未找到对应数据");
		}
		return Result.OK(carInformationUpload);
	}

    /**
    * 导出excel
    *
    * @param request 请求
    * @param carInformationUpload 对象
    */
    @RequestMapping(value = "/exportXls")
    public ModelAndView exportXls(HttpServletRequest request, CarInformationUpload carInformationUpload) {
        return super.exportXls(request, carInformationUpload, CarInformationUpload.class, "进出厂车辆信息上传表");
    }

    /**
      * 通过excel导入数据
    *
    * @param request 请求
    * @param response 响应
    * @return Result
    */
    @RequestMapping(value = "/importExcel", method = RequestMethod.POST)
    public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) {
        return super.importExcel(request, response, CarInformationUpload.class);
    }

	public static Date stringToDate(String dateString) {
		DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
		LocalDateTime localDateTime = LocalDateTime.parse(dateString, formatter);

		// 将LocalDateTime转换为java.util.Date
		ZoneId zoneId = ZoneId.systemDefault();
		return Date.from(localDateTime.atZone(zoneId).toInstant());
	}

}
